//////////////////////////////////////////////////////////////////////
//	filename: 	SpineEventMonitor.h
//	
//	purpose:	Monitor spAnimationState Events
/////////////////////////////////////////////////////////////////////

#pragma once

#include <vector>
#include <string>

// forward declarations
typedef struct spAnimationState spAnimationState;
typedef struct spTrackEntry spTrackEntry;
typedef struct spEvent spEvent;

//////////////////////////////////////////////////////////////////////
//	class: 	SpineEventMonitor
//	
//	purpose:	Monitor spAnimationState Events and report when there
//				are no more spTrackEntry(s) waiting to play on track 0;
//
//				Also allows for debug printing of Events to console.
/////////////////////////////////////////////////////////////////////
class SpineEventMonitor {
public:
	SpineEventMonitor(spAnimationState *_pAnimationState = 0);

	virtual ~SpineEventMonitor();

	void RegisterListener(spAnimationState *_pAnimationState);

	void SetDebugLogging(bool val) { bLogging = val; }

	bool GetDebugLogging() { return bLogging; }

	virtual bool isAnimationPlaying();

protected:
	static void spineAnimStateHandler(spAnimationState *state, int type, spTrackEntry *entry, spEvent *event);

	virtual void
	OnSpineAnimationStateEvent(spAnimationState *state, int type, spTrackEntry *trackEntry, spEvent *event);

protected:
	spAnimationState *pAnimState;
	bool bLogging;
};

//////////////////////////////////////////////////////////////////////
//	class: 	InterruptMonitor
//	
//	purpose:	Allows a programmer to interrupt/stop the updating
//				of an animation based on a specific sequence of
//				events generated by the animation.
/////////////////////////////////////////////////////////////////////
class InterruptMonitor : public SpineEventMonitor {
private:
	struct InterruptEvent {
		InterruptEvent() {
			mEventType = -1; // invalid
			mTrackEntry = 0;
		}

		bool matches(spAnimationState *state, int type, spTrackEntry *trackEntry, spEvent *event);

		std::string mAnimName;
		int mEventType;
		spTrackEntry *mTrackEntry;
		std::string mEventName;
	};

	typedef std::vector<InterruptEvent> InterruptEventStack;


public:
	InterruptMonitor(spAnimationState *_pAnimationState = 0);

	~InterruptMonitor() {}

	virtual bool isAnimationPlaying() override;

public:
	InterruptMonitor &AddInterruptEvent(int theEventType);

	InterruptMonitor &AddInterruptEvent(int theEventType, const std::string &theAnimationName);

	InterruptMonitor &AddInterruptEvent(int theEventType, spTrackEntry *theTrackEntry);

	InterruptMonitor &AddInterruptEventTrigger(const std::string &theEventTriggerName);

protected:
	virtual void
	OnSpineAnimationStateEvent(spAnimationState *state, int type, spTrackEntry *trackEntry, spEvent *event) override;

	virtual void OnMatchingComplete() {}

protected:
	bool bForceInterrupt;
	InterruptEventStack mEventStack; // must match these events in this order
	size_t mEventStackCursor;
};

/*

EXAMPLE
=======

SpineEventMonitor eventMonitor(state);
eventMonitor.SetDebugLogging(true);

while(eventMonitor.isAnimationPlaying()){
	// update...
}



EXAMPLE
=======

InterruptMonitor eventMonitor(state);
eventMonitor.SetDebugLogging(true);

// Interrupt the animation on this specific sequence of spEventType(s)
eventMonitor
	.AddInterruptEvent(SP_ANIMATION_INTERRUPT, "jump")	// First, wait for INTERRUPT signal on the 'jump' animation spTrackEntry
	.AddInterruptEvent(SP_ANIMATION_START);				// Then, stop on any following START signal


*/
